﻿using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;

namespace Apewer.Web
{

    /// <summary>入口集合。</summary>
    public sealed class ApiEntries : IToJson
    {

        #region instance

        object locker = new object();

        SortedDictionary<string, ApiApplication> _apps = new SortedDictionary<string, ApiApplication>();
        SortedDictionary<string, ApiAction> _actions = new SortedDictionary<string, ApiAction>();

        internal ApiApplication GetApplication(string name)
        {
            if (string.IsNullOrEmpty(name)) return null;

            var key = name.ToLower();
            lock (locker)
            {
                if (_apps.TryGetValue(key, out var value)) return value;
            }
            return null;
        }

        internal ApiAction GetAction(string path)
        {
            if (string.IsNullOrEmpty(path)) return null;

            var key = path.ToLower();
            lock (locker)
            {
                if (_actions.TryGetValue(key, out var value)) return value;
            }
            return null;
        }

        /// <summary></summary>
        public ApiApplication[] Applications { get => _apps.Values.Map(x => x); }

        /// <summary></summary>
        public ApiAction[] Actions { get => _actions.Values.Map(x => x); }

        /// <summary></summary>
        public ApiEntries() { }

        /// <summary></summary>
        public ApiEntries(IEnumerable<ApiApplication> applications, IEnumerable<ApiAction> actions, bool replace = false) : this()
        {
            Add(applications, replace);
            Add(actions, replace);
        }

        /// <summary></summary>
        public ApiEntries(IEnumerable<ApiApplication> applications, bool replace = false) : this(applications, null, replace) { }

        /// <summary></summary>
        public ApiEntries(ApiAction[] actions, bool replace = false) : this(null, actions, replace) { }

        /// <summary>添加入口。</summary>
        public void Add(IEnumerable<ApiApplication> applications, bool replace = false)
        {
            if (applications == null) return;
            lock (locker)
            {
                foreach (var app in applications)
                {
                    if (app == null) continue;

                    var appKey = app.Name.Lower();
                    if (appKey.IsEmpty()) continue;

                    if (_apps.ContainsKey(appKey))
                    {
                        if (replace) _apps[appKey] = app;
                    }
                    else
                    {
                        _apps.Add(appKey, app);
                    }
                }
            }
        }

        /// <summary>添加入口。</summary>
        public void Add(IEnumerable<ApiAction> actions, bool replace = false)
        {
            if (actions == null) return;
            lock (locker)
            {
                foreach (var action in actions)
                {
                    if (action == null) continue;

                    var actionKey = action.Path.Lower();
                    if (actionKey.IsEmpty()) continue;

                    if (_actions.ContainsKey(actionKey))
                    {
                        if (replace) _actions[actionKey] = action;
                    }
                    else
                    {
                        _actions.Add(actionKey, action);
                    }
                }
            }
        }

        /// <summary>追加指定的集合，指定 replace 参数将替换当前实例中的同名的入口。</summary>
        public void Add(ApiEntries entries, bool replace = false)
        {
            if (entries == null) return;
            Add(entries.Applications, replace);
            Add(entries.Actions, replace);
        }

        /// <summary>清空当前实例。</summary>
        public void Clear()
        {
            lock (locker)
            {
                _apps.Clear();
                _actions.Clear();
            }
        }

        /// <summary>生成 Json 实例。</summary>
        public Json ToJson()
        {
            lock (locker)
            {
                var obj = new
                {
                    applications = Applications,
                    actions = Actions
                };
                return Json.From(obj);
            }
        }

        #endregion

        #region static

        /// <summary>从指定的程序集获取入口。</summary>
        public static ApiEntries From(Assembly assembly, bool replace = false)
        {
            if (assembly == null) return null;

            var apps = new List<ApiApplication>();
            var actions = new List<ApiAction>();
            var types = assembly.GetExportedTypes();
            foreach (var type in types)
            {
                apps.Add(ApiApplication.Parse(type, true));
                actions.AddRange(ApiAction.Parse(type));
            }

            var entries = new ApiEntries(apps, actions, replace);
            return entries;
        }

        /// <summary>从多个程序集中获取入口。</summary>
        public static ApiEntries From(IEnumerable<Assembly> assemblies, bool replace = false)
        {
            if (assemblies == null) return null;
            var entries = new ApiEntries();
            foreach (var assembly in assemblies) entries.Add(From(assembly), replace);
            return entries;
        }

        /// <summary>从当前程序中获取入口。 </summary>
        public static ApiEntries Calling(bool replace = false) => From(Assembly.GetCallingAssembly(), replace);

        /// <summary>从当前 AppDomain 中获取入口。</summary>
        public static ApiEntries AppDomain(bool replace = false) => From(System.AppDomain.CurrentDomain.GetAssemblies(), replace);

        #endregion

    }

}
